#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<conio.h>//监听键盘 
#include<windows.h>//使用gotoxy函数 
#define MAP_WIDTH 72
#define MAP_HIGH 30
#define MAP_MODE "■"
#define SNAKE_HEAD "●"
#define MOVE_CEN 20
#define INITIAL 3
#define MAXLEN 30

void gotoxy(int x,int y);
void color(int c);
void createMap();
void createFood();
void SNAKE();
void HideCursor();
void move_Snake();
int statement();
void printsnake();
void welcometogame();
void explation();
void gameover();
typedef struct{
	int x;
	int y;
}Food;
Food food;

typedef struct{
	int x[MAXLEN];
	int y[MAXLEN];
	int currentlen; 
}Snake;
Snake snake;
int direct='a';
int point=1;
int grade=0; 

int main()
{   
    HideCursor();
    welcometogame(); 
    return 0;
}
 
void gotoxy(int x,int y)
{
	COORD coord={x,y};
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
	
 }

void printsnake() {//初始界面
    color(7); // 白色 
    gotoxy(15, 5);
    printf("  _________         _________");
    gotoxy(15, 6);
    printf(" /         \\       /         \\");
    gotoxy(15, 7);
    printf("/           \\_____/           \\");
    gotoxy(15, 8);
    printf("\\   Welcome to  the  Snake   /");
    gotoxy(15, 9);
    printf(" \\      Game!      _____    /");
    gotoxy(15, 10);
    printf("  \\               /     \\  /");
    gotoxy(15, 11);
    printf("   \\_____________/       \\/");
}

void welcometogame() {//游戏主体
    system("cls");
    printsnake();
    
    color(11); // 浅蓝色
    gotoxy(25, 14);
    printf("1. 开始游戏");
    gotoxy(25, 15);
    printf("2. 游戏说明");
    gotoxy(25, 16);
    printf("3. 退出游戏 ");
    
    color(14); // 黄色
    gotoxy(15, 19);
    printf("请选择(1-3): ");
    
    char ch = getch();
    switch(ch) {
        case '1':
            system("cls");
            createMap();
	        SNAKE();
	        while(1){
		       Sleep(250);
		       if(point){
			        createFood();
		       }
		    move_Snake();
		    gotoxy(0,MAP_HIGH);
		    printf("当前分数:%d",grade);
		    gameover();
	        } 
            break;
        case '2':
            explation();
            break;
        case '3':
            exit(0);
        default:
            gotoxy(15, 20);
            printf("输入错误，请重新选择!");
            Sleep(500);
            welcometogame();
    }
}

void explation() {
    system("cls");
    color(11);
    gotoxy(20, 3);
    printf("游戏说明");
    color(7);
    gotoxy(10, 5);
    printf("1. 使用方向键控制蛇的移动方向");
    gotoxy(10, 6);
    printf("2. 蛇吃到食物后身体会变长，得分增加");
    gotoxy(10, 7);
    printf("3. 蛇撞到墙壁或自己的身体游戏结束");
    
    gotoxy(10, 15);
    printf("按任意键返回主菜单...");
    getch();
    welcometogame();
}

void createMap()//创建地图
{   
    color(14);
    int i;
    for(i=0+MOVE_CEN;i<MAP_WIDTH+MOVE_CEN;i+=2){
		gotoxy(i,0);
		printf(MAP_MODE);
		gotoxy(i,MAP_HIGH-1);
		printf(MAP_MODE);
	}
	
	
	for(i=0;i<MAP_HIGH;i++){
		gotoxy(0+MOVE_CEN,i);
		printf(MAP_MODE);
		gotoxy(MAP_WIDTH-2+MOVE_CEN,i);
		printf(MAP_MODE);
	}
}

void createFood(){//创建食物
	srand(time(NULL));
	food.x=rand()%(MAP_WIDTH-3)+MOVE_CEN+1;
	food.y=rand()%(MAP_HIGH-2)+1;
	int Being=1;
	if(food.x%2==0){
	for(int i=0;i<snake.currentlen-1;i++){
		if(food.x==snake.x[i]&&food.y==snake.y[i]) Being=0;
	}
	if(Being){
		gotoxy(food.x,food.y);
		color(12);
	    printf(MAP_MODE);
	    point=0;
	    gotoxy(96,0);
	}
}
}

void SNAKE(){//画出蛇身
	snake.x[0]=MAP_WIDTH/2+MOVE_CEN;
    snake.y[0]=MAP_HIGH/2;
    snake.currentlen=INITIAL;
    gotoxy(snake.x[0],snake.y[0]);
    color(10);
    printf(SNAKE_HEAD);
    for(int i=1;i<snake.currentlen;i++){
    	snake.x[i]=snake.x[i-1]+2;
    	snake.y[i]=snake.y[i-1];
    	gotoxy(snake.x[i],snake.y[i]);
    	color(7);
    	printf(SNAKE_HEAD);
	}
}

void move_Snake(){//蛇的移动
	gotoxy(snake.x[snake.currentlen-1],snake.y[snake.currentlen-1]);
	printf(" ");
	for(int i=snake.currentlen-1;i>0;i--){
		snake.x[i]=snake.x[i-1];
		snake.y[i]=snake.y[i-1];
		gotoxy(snake.x[i],snake.y[i]);
		color(7);
		printf(SNAKE_HEAD);
	}
	if(_kbhit()){
	
		fflush(stdin);
		direct=_getch();
		
	}
		
	
	switch(direct){
		case 'w':
		case 'W':
			snake.y[0]--;
			break;
		case 's':
		case 'S':
			snake.y[0]++;
			break;
		case 'a':
		case 'A':
	        snake.x[0]-=2;
			break;
		case 'd':
		case 'D':
			snake.x[0]+=2;
			break;
	}
	gotoxy(snake.x[0],snake.y[0]);
	color(10);
	printf(SNAKE_HEAD);
	if(food.x==snake.x[0]&&food.y==snake.y[0]){
		snake.currentlen++;
		grade+=10;
		point=1;
	}
	gotoxy(96,0);
}

int statement(){//判断游戏状态
	if(snake.x[0]==0+MOVE_CEN||snake.x[0]==MAP_WIDTH-2+MOVE_CEN||snake.y[0]==0||snake.y[0]==MAP_HIGH-1) return 1;
	for(int i=1;i<snake.currentlen;i++){
		if(snake.x[0]==snake.x[i]&&snake.y[0]==snake.y[i]) return 1;
	}
	return 0;
}
void gameover(){//游戏结束
	if(statement()){
		      system("cls");
			  gotoxy(MAP_WIDTH/2+MOVE_CEN-6,MAP_HIGH/2);
			  printf("Game over!你的最终分数是%d",grade);
		      gotoxy(MAP_WIDTH/2+MOVE_CEN-6,MAP_HIGH/2+1);
		      printf("1.再来一次");
			  gotoxy(MAP_WIDTH/2+MOVE_CEN-6,MAP_HIGH/2+2); 
			  printf("2.无聊不来了");
	char ch;
    do {
        ch = getch();
        if (ch == '1') {
            system("cls");
            grade = 0;
            direct='a';
            welcometogame();
        }
        else if (ch == '2') {
            exit(0);
        }
        else {
            gotoxy(20, 15);
            printf("选择错误，请重新选择!");
        }
    } while (ch != '1' && ch != '2');
}
}
void color(int c) {//颜色改变
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
void HideCursor() {//光标隐藏
    CONSOLE_CURSOR_INFO curInfo;
    curInfo.dwSize = 1;
    curInfo.bVisible = FALSE;
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorInfo(handle, &curInfo);
}
